package com.pansoft.resmanager;


import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Looper;
import android.util.Base64;
import android.util.Log;

import com.pansoft.appcontext.AppConstant;
import com.pansoft.resmanager.ResFileManager.DownloadType;

/**
 * 管理下载的资源文件(表单, 菜单, 图片等)
 * 
 * @author zhangjg
 * @date Jan 6, 2014 4:58:49 PM
 */
public class ResFileManager_moble {
	
	private static final String TAG = "ResFileManager";

	//资源文件所在的根路径, zip文件下载到该目录
	//public static final String RES_DIR = Environment.getExternalStorageDirectory()+"/ESPMobile/res";
	public static final String RES_DIR = AppConstant.APP_ROOT+"/res";
	
	//zip文件解压到的资源目录
	public static final String UNZIP_DIR = RES_DIR + "/" + "unzip_res";
	
	//图片所在目录
	public static final String IMAGE_DIR = UNZIP_DIR + "/" + "Image";
	
	//表单所在路径
	public static final String FORM_DIR = UNZIP_DIR + "/" + "Form";
	
	//菜单所在路径
	public static final String PACKAGE_DIR = UNZIP_DIR + "/" + "Package";
	
	
	
	//更新时将update.zip解压到临时目录
	public static final String UNZIP_TEMP_DIR = RES_DIR + "/" + "unzip_temp";
	
	//临时图片目录
	public static final String TEMP_IMAGE_DIR = UNZIP_TEMP_DIR + "/" + "Image";
	
	//临时菜单目录
	public static final String TEMP_PACKAGE_DIR = UNZIP_TEMP_DIR + "/" + "Package";

	//临时表单目录
	public static final String TEMP_FORM_DIR = UNZIP_TEMP_DIR + "/" + "Form";
	
	
	static{
		
		//创建 /sdcard/ESPMobile/res
		File resDir = new File(RES_DIR);    
		if(!resDir.exists()){
			resDir.mkdirs();
		}
		
		//创建  /sdcard/ESPMobile/res/unzip_res
		File uzipDir = new File(UNZIP_DIR);	
		if(!uzipDir.exists()){
			uzipDir.mkdirs();
		}
		
		//创建  /sdcard/ESPMobile/res/unzip_temp
		File uzipTempDir = new File(UNZIP_TEMP_DIR);	
		if(!uzipTempDir.exists()){
			uzipTempDir.mkdirs();
		}
	}
	
	/**
	 * 下载资源
	 * 下载之后直接解压和加密
	 */
	public static void downloadRes(String url, final DownloadType type, final ResCallback callback){
		String filePath = getFilePathFromUrl(url);
		
		File zipFile = new File(filePath);
		if(zipFile.exists()){
			zipFile.delete();
		}
		
		
		//同步下载, 必须放到子线程
		downloadResSync(url, filePath);
		
		//解压文件并加密
		unzipAndEncryptFile(filePath, type);
		
		//删除下载的源文件
		zipFile.delete();
		
		//回调
		new Handler(Looper.getMainLooper()).post(new Runnable() {
			
			@Override
			public void run() {
				if(callback != null){
					callback.onSuccess(type);
				}
			}
		});
	}
	
	/**
	 * 根据文件名获取图标
	 * @param fileName 文件名, 不包括路径
	 * @return 可能返回空, 使用该方法的执行结果需要判空
	 */
	public Bitmap getDrawableRes(String fileName){
		
		String imageFilePath = IMAGE_DIR + "/" + fileName;
		InputStream in = getFile(imageFilePath);
		 
//		if(in != null){
			Bitmap bm = BitmapFactory.decodeStream(in);
			
//		}
//		else{
//			return null;
//		}
		return bm;
	}
	
	/**
	 * 根据文件名获取表单
	 * @param fileName 文件名, 不包括路径
	 * @return 可能返回空, 使用该方法的执行结果需要判空
	 */
	public InputStream getFormRes(String fileName){
		
		String formFilePath = FORM_DIR + "/" + fileName;
		return getFile(formFilePath);
		
	}
	
	/**
	 * 根据文件名获取菜单
	 * @param fileName 文件名, 不包括路径
	 * @return 可能返回空, 使用该方法的执行结果需要判空
	 */
	public InputStream getMenuRes(String fileName){
		String formFilePath = PACKAGE_DIR + "/" + fileName;
		return getFile(formFilePath);
	}
	
	/**
	 * 获取资源文件
	 * @param filePath 文件绝对路径
	 * @return
	 */
	public static InputStream getFile(String filePath){
		
		
//		InputStream in = null;
//		try {
//			in = new FileInputStream(filePath);
//			
//		} catch (FileNotFoundException e) {
//			Log.i(TAG, "文件" + filePath + "不存在");
//			e.printStackTrace();
//		}
//		return in;
		
		//读取之前必须先解密文件
		return decryptFile(filePath);
	}

	
	/**
	 * 解压文件并加密
	 */
	private static void unzipAndEncryptFile(String filePath, DownloadType type){
		
		//删除原有的解压缩后的文件
		//deleteUnzipRes();
		ZipUtil zUtil = new ZipUtil();
		if(type == DownloadType.INIT){  //初始化
			Log.i(TAG, "init, 第一次下载资源");
			
			zUtil.unZip(filePath, UNZIP_DIR);
			//encryptAllRes();   //加密所有文件
			
		}else if(type == DownloadType.UPDATE){
			
			Log.i(TAG, "update, 更新资源");
			
			//将更新的zip解压到临时目录
			zUtil.unZip(filePath, UNZIP_TEMP_DIR);
			
			//encryptAllTempRes();
			
			//将加密后的要更新的文件拷贝到资源目录
			copyTempFileToRes();
			
			//删除临时目录中的文件
			deleteTempRes();
		}
		
	} 
	
	/**
	 * 删除临时目录中的文件(不会删除目录结构)
	 */
	private static void deleteTempRes(){
		File tempResRootDir = new File(UNZIP_TEMP_DIR);
		
		for(File resDir : tempResRootDir.listFiles()){
			deleteFileOfDir(resDir.getAbsolutePath());
		}
	}
	/**
	 * 将临时资源文件拷贝到资源目录
	 */
	private static void copyTempFileToRes(){
		copyFile(TEMP_FORM_DIR, FORM_DIR);
		copyFile(TEMP_IMAGE_DIR, IMAGE_DIR);
		copyFile(TEMP_PACKAGE_DIR, PACKAGE_DIR);
	}
	
	
	/**
	 * 删除一个目录下的所有文件, 如果目录下存在目录, 则不会递归删除
	 * @param resDir 资源文件所在的父目录
	 */
	private static void deleteFileOfDir(String dir){
		deleteFileOfDir(new File(dir));
	}
	
	/**
	 * 删除一个目录下的所有文件, 如果目录下存在目录, 则不会递归删除
	 * @param resDir 资源文件所在的父目录
	 */
	private static void deleteFileOfDir(File dir){
		
		if((!dir.exists())) {  
			Log.i(TAG, "要删除的目录" + dir.getAbsolutePath() + "不存在, 删除失败");
			return;
		}
		
		if(!dir.isDirectory()){
			Log.i(TAG, "要删除的目录" + dir.getAbsolutePath() + "不是目录, 删除失败");
			return;
		}

		for(File f : dir.listFiles()){
			if(f.isFile()){
				f.delete();
			}
		}
	}
	
	/**
	 * 复制文件, 复制后文件名不变
	 * @param resDir	原文件所在目录
	 * @param desDir	目标目录
	 */
	private static void copyFile(String resDir, String desDir){
		File _resDir = new File(resDir);
		File _desDir = new File(desDir);
		
		if((!_resDir.exists()) || (!_desDir.exists())){  //如果目录不存在
			return;
		}
		
		
		for(File f : _resDir.listFiles()){
			if(!f.isFile()){
				continue;
			}
			
			String name = f.getName();
			File desFile = new File(desDir + "/" + name);
			
			if(desFile.exists()){
				desFile.delete();
			}
			
			copyAFile(f, desFile);
			
		}
	}
	
	/**
	 * 复制一个文件
	 * @param resFile
	 * @param desFile
	 */
	private static void copyAFile(File resFile, File desFile){
		BufferedInputStream bufIn = null; 
		BufferedOutputStream bufOut = null;
		
		try {
			bufIn = new BufferedInputStream(new FileInputStream(resFile));
			bufOut = new BufferedOutputStream(new FileOutputStream(desFile));
			int len = 0;
			byte[] buffer = new byte[1024];
			
			while((len = bufIn.read(buffer)) != -1){
				bufOut.write(buffer, 0, len);
			}
			
		} catch (Exception e) {
			Log.i(TAG, "复制临时文件" + resFile.getAbsolutePath() + "时出现错误, 复制失败");
			e.printStackTrace();
		}finally{
			
			if(bufIn != null){
				try {
					bufIn.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			
			if(bufOut != null){
				try {
					bufOut.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		
		
	}
	
	/**
	 * 获取要下载的文件的本地储存路径
	 * 该路径是绝对路径
	 * @param url
	 * @return
	 */
	private static String getFilePathFromUrl(String url) {
		
		String fileName = url.substring(url.lastIndexOf("/") + 1); 
		return RES_DIR + "/" + fileName;
	}
	
	/**
	 * init时对所有资源进行加密
	 */
	private static void encryptAllRes(){

		File resRootDir = new File(UNZIP_DIR);
		
		for(File resDir : resRootDir.listFiles()){
			encryptDir(resDir);
		}
//		encryptDir(new File(IMAGE_DIR));
//		encryptDir(new File(PACKAGE_DIR));
//		encryptDir(new File(FORM_DIR));
	}
	
	/**
	 * 更新时对所有临时资源加密
	 */
	private static void encryptAllTempRes(){
		
		File tempRootDir = new File(UNZIP_TEMP_DIR);
		
		for(File tempResDir : tempRootDir.listFiles()){
			encryptDir(tempResDir);
		}

//		encryptDir(new File(TEMP_IMAGE_DIR));
//		encryptDir(new File(TEMP_PACKAGE_DIR));
//		encryptDir(new File(TEMP_FORM_DIR));
	}
	
	/**
	 * 将文件夹下的所有文件分别加密(不会递归加密文件夹)
	 */
	private static void encryptDir(File dirToEncrypt){
		
		for(File file : dirToEncrypt.listFiles()){
			if(file.exists() && file.isFile()){
				encryptFile(file.getAbsolutePath());
			}
		}
	}
	
	
	/***
	 * 返回一个xml的String形式
	 * @param file
	 * @return
	 */
	@SuppressWarnings("resource")
	public static String decryptFile(File file) {
		String result = null;
		// String filePath = file.toString();
		try {
			FileReader fr = new FileReader(file);
			BufferedReader br = new BufferedReader(fr);
			String s = null;
			StringBuilder sb = new StringBuilder();

			while ((s = br.readLine()) != null) {
				sb.append(s);
			}

			result = sb.toString();
			String all =Base64.encodeToString(sb.toString().getBytes(), Base64.DEFAULT);
			byte[] allBytes = Base64.decode(all, Base64.DEFAULT);
			//byte[] decryData = Des3.des3DecodeCBC(allBytes);
			
			//result = new String(decryData);
			
			Log.i("DES", result);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return result;
	}
	
	
	/**
	 * 加密文件
	 * @param filePath  文件绝对路径, 加密之后文件名不变, 覆盖原文件
	 */
	@SuppressWarnings("resource")
	private static void encryptFile(String filePath){
		
		/**
		 * huayang 只加密xml文件
		 */
		Log.i("tag",(FileUtils.getExtensionName(filePath)));
		if(!"xml".equals(FileUtils.getExtensionName(filePath))){
			return;
		}
		
//		File sdDir = Environment.getExternalStorageDirectory();
//		String [] array = sdDir.list();
//		FileInputStream in = null;
//		ByteArrayOutputStream byOut = null;
//		FileOutputStream out = null;
//		try {
//			//File file = new File(filePath);
//			in = new FileInputStream(filePath);
//			BufferedInputStream bis = new BufferedInputStream(in);
//			
//			
//			byOut = new ByteArrayOutputStream();
////			out = new FileOutputStream(filePath);
//			
//			byte[] buffer = new byte[1024];
//			
//			int len = 0;
//			len = in.read(buffer);
//			len = bis.read(buffer);
//			while((len = in.read(buffer)) != -1){
//				byOut.write(buffer, 0, len);
//			}
//			byte[] b =  byOut.toByteArray();
//			byte[] encodedByteArray = Des3.des3EncodeCBC(byOut.toByteArray());
//			
//			out = new FileOutputStream(filePath);
//			out.write(encodedByteArray);
		try{
			
			FileReader fr = new FileReader(new File(filePath));
			BufferedReader br = new BufferedReader(fr);
			String s = null;
			StringBuilder sb = new StringBuilder();
			
			while((s = br.readLine()) != null){
				sb.append(s);
			}
			
			String all = sb.toString();
			byte[] data = all.getBytes();
			Log.i("LEN :"," byte[] data = all.getBytes(); " + data.length);	
			
			byte[] encodedByteArray = Des3.des3EncodeCBC(data);
			Log.i("LEN :"," 加密完后的长度" + encodedByteArray.length);	
			Log.i("LEN :","加密 ：\n" + new String(encodedByteArray));
			
			byte[] back = Des3.des3DecodeCBC(encodedByteArray);
			Log.i("LEN :","恢复 ：\n" + new String(back));
			Log.i("LEN :"," 解密完后的长度" + back.length);
			
			FileOutputStream fout = new FileOutputStream(filePath,false);
			BufferedOutputStream bout = new BufferedOutputStream(fout);
			bout.write(encodedByteArray);
			bout.flush();
			bout.close();
			
			fr.close();
			br.close();
		} catch (Exception e) {
			e.printStackTrace();
			Log.i(TAG, "文件" + filePath + "在加密过程中出现错误, 加密失败");
		}finally{
			
//			if(in != null){
//				try {
//					in.close();
//				} catch (IOException e) {
//					e.printStackTrace();
//				}
//			}
//			
//			if(out != null){
//				try {
//					out.close();
//				} catch (IOException e) {
//					e.printStackTrace();
//				}
//			}
//			
//			if(byOut != null){
//				try {
//					byOut.close();
//				} catch (IOException e) {
//					e.printStackTrace();
//				}
//			}
		}
	}
	
	/**
	 * 解密文件
	 * @param filePath
	 */
	private static InputStream decryptFile(String filePath){
		
		FileInputStream in = null;
		ByteArrayOutputStream byOut = null;
		ByteArrayInputStream byIn = null;
		try {
			byOut = new ByteArrayOutputStream();
			in = new FileInputStream(filePath);
			byte[] buffer = new byte[1024];
			int len = 0;
			while((len = in.read(buffer)) != -1){
				byOut.write(buffer, 0, len);
			}
			
			byte[] decodedByteArray = Des3.des3EncodeCBC(byOut.toByteArray());
			
			byIn = new ByteArrayInputStream(decodedByteArray);
		} catch (Exception e) {
			e.printStackTrace();
			Log.i(TAG, "文件" + filePath + "在解密过程中出现错误, 解密失败");
		}finally{
			if(in != null){
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			
			if(byOut != null){
				try {
					byOut.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return byIn;
	}
	
	/**
	 * 同步下载
	 */
	private static void downloadResSync(String url, String filePath){
		/*
		HttpUtils http = new HttpUtils();
		http.configCurrentHttpCacheExpiry(1000*10);
		http.configRequestThreadPoolSize(3);
		ResponseStream responseStream = null;
		
		try {
			responseStream = http.sendSync(HttpRequest.HttpMethod.GET, 
					url);
			
			responseStream.readFile(filePath);
			
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			
			if(responseStream != null){
				try {
					responseStream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}*/
	}
	
/*	public static enum DownloadType{
		INIT,
		UPDATE
	}*/
	
}
